from py2neo import Graph

# 加载图数据库
try:
	graph = Graph("bolt://localhost:7687")
except Exception as e:
    print('Error:'+str(e))

# 查询所有包含关键字 ss 的节点
def KeyWrodSearch(ss):
    try:
        ss=ss.replace('*','\\\*').replace('+','\\\+').replace('.','\\\.')
        ndls=graph.run('MATCH (n:Tech) WHERE n.name=~"(?i).*'+ss+'.*" RETURN n')
        return [nds[0]['name'] for nds in ndls]
    except Exception as e:
        return (False,'Error:'+str(e))

# 返回所有的根节点
def FindRoots():
    try:
        ndls=graph.run('MATCH (b:Tech)<-[r]-() RETURN b')
        return set([nds[0]['name'] for nds in ndls])
    except Exception as e:
        return (False,'Error:'+str(e))

# 返回同义子节点
def SynonymOf(ss):
    ndls=graph.run('MATCH (h:Tech{name:"'+ss+'"})<-[r:SynonymOf]-(l) RETURN l')
    return [nds[0]['name'] for nds in ndls]

# 返回实例子节点
def InstanceOf(ss):
    ndls=graph.run('MATCH (h:Tech{name:"'+ss+'"})<-[r:InstanceOf]-(l) RETURN l')
    return [nds[0]['name'] for nds in ndls]

# 返回同义父节点
def SynonymFatherOf(ss):
    ndls=graph.run('MATCH (h:Tech{name:"'+ss+'"})-[r:SynonymOf]->(l) RETURN l')
    return [nds[0]['name'] for nds in ndls]

# 返回实例父节点
def InstanceFatherOf(ss):
    ndls=graph.run('MATCH (h:Tech{name:"'+ss+'"})-[r:InstanceOf]->(l) RETURN l')
    return [nds[0]['name'] for nds in ndls]

# 检查节点是否为叶子节点,若否则返回同义父节点
def IfSonGetFather(ss):
    syn=SynonymOf(ss)
    ins=InstanceOf(ss)
    if len(syn+ins)==0:
        asd=SynonymFatherOf(ss)
        if len(asd)>0:
            ss=asd[0]
    return ss

# 递归返回节点所有同义节点和实例子节点
def RelativesOf(ss,count = 0):
    try:
        if count>25:
            return (False,'Error:递归查询次数超出限制')
        dic={}
        dic['key']=ss
        ss=IfSonGetFather(ss)
        dic['alias']=SynonymOf(ss)+[ss]
        dic['value']=[RelativesOf(son,count + 1) for son in InstanceOf(ss)]
        if (False,'Error:递归查询次数超出限制') in dic['value']:
            return (False,'Error:递归查询次数超出限制')
        return dic
    except Exception as e:
        return (False,'Error:'+str(e))

# 删除节点
def DeleteNode(ss):
    try:
        graph.run('MATCH (s:Tech{name:"'+ss+'"})-[r]-() DELETE r')
        graph.run('MATCH (s:Tech{name:"'+ss+'"}) DELETE s')
        return True
    except Exception as e:
        return (False,'Error:'+str(e))

# 删除关系
def DeleteRelation(root,leaf):
    try:
        graph.run('MATCH (h:Tech{name:"'+root+\
            '"})-[r]-(l:Tech{name:"'+leaf+'"}) DELETE r')
        root=IfSonGetFather(root)
        graph.run('MATCH (h:Tech{name:"'+root+\
            '"})-[r]-(l:Tech{name:"'+leaf+'"}) DELETE r')
        return True
    except Exception as e:
        return (False,'Error:'+str(e))

# 新建节点
def NewNode(ss):
    try:
        graph.run('MERGE (s:Tech{name:"'+ss+'"})')
        return True
    except Exception as e:
        return (False,'Error:'+str(e))

# 新建关系
def NewRelation(root,leaf,rltp):
    try:
        if root!=leaf:
            graph.run('\
            MERGE (b:Tech{name:"'+root+'"})\
            MERGE (l:Tech{name:"'+leaf+'"})\
            MERGE (b)<-[r:'+rltp+']-(l)')  
        return True
    except Exception as e:
        return (False,'Error:'+str(e))

# 新建关系,加规则约束
def NewRelationAndMerge(root,leaf,rltp):
    try:
        root=IfSonGetFather(root)
        if rltp=='SynonymOf':
            syn=SynonymOf(leaf)
            ins=InstanceOf(leaf)
            insf=InstanceFatherOf(leaf)
            if len(syn+ins+insf)!=0:
                DeleteNode(leaf)
                for nd in syn:
                    NewRelation(root,nd,'SynonymOf')
                for nd in ins:
                    NewRelation(root,nd,'InstanceOf')
                for nd in insf:
                    nd=IfSonGetFather(nd)
                    NewRelation(nd,root,'InstanceOf')
            NewRelation(root,leaf,'SynonymOf')
        if rltp=='InstanceOf':
            ndls=graph.run('MATCH (h:Tech{name:"'+root+\
                '"})-[r:InstanceOf]->(l:Tech{name:"'+leaf+'"}) RETURN r')
            if len(list(ndls))>0:
                return (False,'Error:'+root+'已是'+leaf+'的包含子节点')
            else:
                NewRelation(root,leaf,'InstanceOf')
        return True
    except Exception as e:
        return (False,'Error:'+str(e))

# 重命名节点
def ModifyNode(OldName,NewName):
    try:
        ndls=graph.run('MATCH (b:Tech{name:"'+NewName+'"}) RETURN b')
        if len(list(ndls))>0:
            syn=SynonymOf(OldName)
            ins=InstanceOf(OldName)
            synf=SynonymFatherOf(OldName)
            insf=InstanceFatherOf(OldName)
            if len(syn+ins+synf+insf)!=0:
                DeleteNode(OldName)
                NewName=IfSonGetFather(NewName)
                for nd in syn:
                    NewRelation(NewName,nd,'SynonymOf')
                for nd in ins:
                    NewRelation(NewName,nd,'InstanceOf')
                for nd in synf:
                    nd=IfSonGetFather(nd)
                    NewRelation(nd,NewName,'SynonymOf')
                for nd in insf:
                    nd=IfSonGetFather(nd)
                    NewRelation(nd,NewName,'InstanceOf')
        else:
            graph.run('MATCH (s:Tech{name:"'+OldName+'"}) SET s.name="'+NewName+'"')
        return True
    except Exception as e:
        return (False,'Error:'+str(e))
